package sonic.game.animation;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;

/**
 * Animation
 * @author RGreenlees
 *
 * Handles animation. An array of images which will loop through based on the speed of the animation.
 */

public class Animation {

	// The frames of the animation
	public ArrayList<BufferedImage> frames = new ArrayList<BufferedImage>();
	// Allow the play speed of the animation to change (e.g. Sonic's run and roll animation)
	public float defaultAnimTime = 1.0f;
	public float currentAnimTime = 1.0f;
	// This is calculated on the fly based on the number of frames and specified play time
	private float timeBetweenFrames;
	// Current frame the animation is on
	private int currentFrame = 0;
	// Used to check when the frame needs to change
	private double timer = 0.0d;
	// If looping, this will become true after the first play
	public boolean bFinished = false;
	public boolean bLooping = true;
	
	public Animation(float pAnimTime, BufferedImage ... buffImgs)
	{
		for (BufferedImage a : buffImgs)
		{
			frames.add(a);
		}
		defaultAnimTime = pAnimTime;
		currentAnimTime = pAnimTime;
		timeBetweenFrames = currentAnimTime/frames.size();
		currentFrame = 0;
		
	}
	
	/** Restart the animation */
	public void reset()
	{
		currentFrame = 0;
		timer = 0.0d;
		bFinished = false;
	}
	
	public Animation(float pAnimTime, boolean pLooping, String ...imgLocations)
	{
		BufferedImage img;
		for (String a : imgLocations)
		{
			try
			{
				img = ImageIO.read(new File(a));
				frames.add(img);
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
		}
		
		defaultAnimTime = pAnimTime;
		currentAnimTime = pAnimTime;
		timeBetweenFrames = currentAnimTime/frames.size();
		currentFrame = 0;
		bLooping = pLooping;
	}
	
	public Animation(float pAnimTime, boolean bLooping, ArrayList<BufferedImage> newFrames)
	{
		for (BufferedImage a : newFrames)
		{
			frames.add(a);
		}
		defaultAnimTime = pAnimTime;
		currentAnimTime = pAnimTime;
		timeBetweenFrames = currentAnimTime/frames.size();
		currentFrame = 0;
		
	}
	
	/** Manually add a new frame to the end of the existing animation */
	public void addFrame(String newFrame)
	{
		try
		{
			BufferedImage img = ImageIO.read(new File(newFrame));
			frames.add(img);
			setAnimRate(1.0f);
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	

	
	public Animation(float pAnimTime, boolean loop, BufferedImage ... buffImgs)
	{
		for (BufferedImage a : buffImgs)
		{
			frames.add(a);
		}
		defaultAnimTime = pAnimTime;
		currentAnimTime = pAnimTime;
		timeBetweenFrames = currentAnimTime/frames.size();
		currentFrame = 0;
		bLooping = loop;
		
	}
	
	/** Used to retrieve the frame needed to draw the animated tile on the screen */
	public BufferedImage getCurrentFrame()
	{
		return frames.get(currentFrame);
	}
	
	/** Overloaded method specifying if the frame should be flipped horizontally or not (for facing left/right) */
	public BufferedImage getCurrentFrame(boolean pReversed)
	{
		if (!pReversed)
		{
			return frames.get(currentFrame);
		}
		else
		{
			return horizontalFlip(frames.get(currentFrame));
		}
	}
	
	/** Horizontally flips the BufferedImage */
	public BufferedImage horizontalFlip(BufferedImage img)
	{   
        int w = img.getWidth();   
        int h = img.getHeight();   
        BufferedImage dimg = new BufferedImage(w, h, img.getColorModel().getTransparency());     
        Graphics2D g = dimg.createGraphics();   
        g.drawImage(img, 0, 0, w, h, w, 0, 0, h, null);   
        g.dispose();   
        return dimg;   
    }  
	
	/** Horizontally flips the BufferedImage. Not currently used by may come in handy */
	public BufferedImage verticalFlip(BufferedImage img)
	{   
        int w = img.getWidth();   
        int h = img.getHeight();   
        BufferedImage dimg = new BufferedImage(w, h, img.getColorModel().getTransparency());   
        Graphics2D g = dimg.createGraphics();   
        g.drawImage(img, 0, 0, w, h, 0, h, w, 0, null);   
        g.dispose();   
        return dimg;   
    }  
	
	/** Modify playback speed as a percentage of default speed */
	public void setAnimRate(float newRate)
	{
		currentAnimTime = defaultAnimTime / newRate;
		timeBetweenFrames = currentAnimTime/frames.size();
	}
	
	/** Run the timer and start running through the animation frames */
	public void update(double deltaTime)
	{
		if (frames.size() > 1 && (bLooping || !bFinished))
		{
			timer += deltaTime;
			if (timer > Math.abs(timeBetweenFrames))
			{
				if (timeBetweenFrames < 0)
				{
					currentFrame--;
				}
				else
				{
					currentFrame++;
				}
				timer = 0.0f;
			}
		
			if (timeBetweenFrames > 0)
			{
				if (currentFrame > frames.size()-1)
				{
					if (!bLooping)
					{
						currentFrame = frames.size()-1;
					}
					else
					{
						currentFrame = 0;
					}
					bFinished=true;
				}
			}
			else
			{
				if (currentFrame < 0)
				{
					currentFrame = frames.size()-1;
					bFinished=true;
				}
			}
		}
	}
}
